//
// Created by LONG on 2020/10/18.
//

#include <stdio.h>
#include <iostream>
#include "../lib/doctest.h"
#include "../../include/utils/list.h"
#include "../../include/utils/listSort.h"

using namespace std;

#define LOOP_TIMES 100000


typedef struct SortInst4Ut
{
    S_List node;
    uint32_t priority;
} S_SortInst4Ut;

int32_t ut_list_cmp(S_List *a, S_List *b)
{
    S_SortInst4Ut *instA;
    S_SortInst4Ut *instB;
    instA = CONTAINER_OF(a, S_SortInst4Ut, node);
    instB = CONTAINER_OF(b, S_SortInst4Ut, node);

    if (instA->priority > instB->priority)
    {
        return 1;
    }
    else if (instA->priority < instB->priority)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}

TEST_SUITE ("LIST_TS")
{
    TEST_CASE ("LIST_TC")
    {
        SUBCASE("LIST_SC_BASE1")
        {
            uint32_t loop;
            S_List list;
            S_List *node;

            LIST_Init(&list);

            for (loop = 0; loop < LOOP_TIMES; loop++)
            {
                node = (S_List *)malloc(sizeof(S_List));
                LIST_Append(&list, node);
            }
            REQUIRE_FALSE(LIST_Empty(&list));

            loop = 0;
            LIST_FOR_EACH_SAFE(node, &list)
            {
                LIST_Remove(node);
                free(node);
                loop++;
            }
            REQUIRE((uint32_t)LOOP_TIMES == loop);
            REQUIRE(LIST_Empty(&list));
        }

        SUBCASE("LIST_SC_BASE2")
        {
            uint32_t loop;
            S_List list;
            S_List *node;

            LIST_Init(&list);

            for (loop = 0; loop < LOOP_TIMES; loop++)
            {
                node = (S_List *)malloc(sizeof(S_List));
                LIST_Prepend(&list, node);
            }
            REQUIRE_FALSE(LIST_Empty(&list));

            loop = 0;
            LIST_FOR_EACH_SAFE(node, &list)
            {
                LIST_Remove(node);
                free(node);
                loop++;
            }
            REQUIRE((uint32_t)LOOP_TIMES == loop);
            REQUIRE(LIST_Empty(&list));
        }

        SUBCASE("LIST_SC_BASE3")
        {
            uint32_t loop;
            S_List list;
            S_List node[LOOP_TIMES];

            LIST_Init(&list);

            for (loop = 0; loop < LOOP_TIMES; loop++)
            {
                LIST_Prepend(&list, &node[loop]);
            }
            REQUIRE_FALSE(LIST_Empty(&list));

            LIST_Final(&list);
            REQUIRE(LIST_Empty(&list));
        }

        SUBCASE("LIST_SC_JOIN")
        {
            uint32_t loop;
            S_List *node;
            S_List list1, list2;
            S_List node1[LOOP_TIMES];
            S_List node2[LOOP_TIMES];

            LIST_Init(&list1);
            LIST_Init(&list2);

            LIST_Join(&list1, &list2);
            loop = 0;
            LIST_FOR_EACH_SAFE(node, &list1)
            {
                loop++;
            }
            REQUIRE_EQ(loop, 0);

            for (loop = 0; loop< LOOP_TIMES; loop++)
            {
                LIST_Append(&list1, &node1[loop]);
            }
            LIST_Join(&list1, &list2);
            loop = 0;
            LIST_FOR_EACH_SAFE(node, &list1)
            {
                loop++;
            }
            REQUIRE_EQ(loop, LOOP_TIMES);

            LIST_Join(&list2, &list1);
            REQUIRE(LIST_Empty(&list1));
            loop = 0;
            LIST_FOR_EACH_SAFE(node, &list2)
            {
                loop++;
            }
            REQUIRE_EQ(loop, LOOP_TIMES);

            for (loop = 0; loop < LOOP_TIMES; loop++)
            {
                LIST_Append(&list2, &node2[loop]);
            }
            LIST_Join(&list1, &list2);
            REQUIRE(LIST_Empty(&list2));
            loop = 0;
            LIST_FOR_EACH_SAFE(node, &list1)
            {
                loop++;
            }
            REQUIRE_EQ(loop, LOOP_TIMES * 2);

            LIST_Final(&list1);
            REQUIRE(LIST_Empty(&list1));
            LIST_Final(&list2);
            REQUIRE(LIST_Empty(&list2));
        }

        SUBCASE("LIST_SC_SORT")
        {
#define SORT_INST_NUM 100000

            uint32_t loop;
            uint32_t priority;
            S_List list;
            S_SortInst4Ut *inst;
            S_SortInst4Ut sortInst[SORT_INST_NUM];

            LIST_Init(&list);

            for (loop = 0; loop < SORT_INST_NUM; loop++)
            {
                sortInst[loop].priority = rand();
                LIST_Prepend(&list, &sortInst[loop].node);
            }
            REQUIRE_FALSE(LIST_Empty(&list));

            LIST_Sort(&list, ut_list_cmp);

            priority = 0;
            LIST_FOR_EACH_ENTRY_SAFE(inst, &list, node)
            {
                REQUIRE_LE(priority, inst->priority);
                priority = inst->priority;
            }

            LIST_Final(&list);
            REQUIRE(LIST_Empty(&list));
        }
    }
}

